package meshToSolid;

import grid.Grid3DFloat;
import hdgeom.bezier.Bezier;
import hdgeom.primitives.Box;
import importExport.SimpleOBJExporter;
import importExport.SimpleSimpleOBJExporter;

import java.awt.geom.GeneralPath;

import mmesh.MMesh;
import peasy.PeasyCam;
import processing.core.PApplet;
import processing.core.PGraphics;
import processing.core.PVector;
import simpleGeom.HasPos2D;
import simpleGeom.Polygon2D;

public class BezierApplet extends PApplet {
	PeasyCam cam;
	MMesh mesh;
	Box boundsCrop = new Box(-1.575f, -1.7534246f, 0.015989847f, 0.01f,
			1.4465753f, 2.14f);

	public void setup() {
		size(800, 600, P3D);
		cam = new PeasyCam(this, 400);
		
	}
	public void display(PGraphics g){
		int nY = 200;
		float dY = boundsCrop.getDimY() / nY;
		;
		for (int y = 0; y < nY; y++) {
			float cY = y * dY + boundsCrop.y1;
			
			g.pushMatrix();
			g.translate(0, y * dY + boundsCrop.y1, 0);
			//border.display(g);
			Polygon2D border1=crop2(cY);;
			border=crop2((y+1) * dY + boundsCrop.y1);
			g.beginShape(QUAD_STRIP);
			for (int i=0;i<border1.getNPts();i++){
				HasPos2D v1=border1.get(i);
				HasPos2D v2=border.get(i);
				g.vertex(v1.getX(),0,v1.getY());
				g.vertex(v2.getX(),dY,v2.getY());
			}
			g.endShape();
			g.popMatrix();
			
		}
	}
	boolean doExport=true;
	public void draw() {
		background(255);
		scale(100);
		
		noStroke();
		fill(255);
		//lights();
		pointLight(220,200,200,-10,-10,0);
		pointLight(200,200,220,4,4,4);
		
		display(g);
		
		g.scale(-1,1,1);
		display(g);
		
		if (doExport){
			SimpleSimpleOBJExporter sobj=new SimpleSimpleOBJExporter("testHull.obj");
			display(sobj);
			g.scale(-1,1,1);
			display(sobj);
			sobj.dispose();
			doExport=false;
		}
		
	}

	Polygon2D border;

	public void crop(float y) {
		// if (outsideCrop) distance to line
		// if (insideCrop and unreached)
		float z2 = boundsCrop.z2 - 0.2f;
		// smaller iso->inside
		float zM = 1.5f;
		float wave = 1f;
		float amp = 0.1f;
		float startY = 0;
		float dZ = 0;
		float cY = y - startY;
		if (cY > 0 && cY < wave) {
			dZ = sin(cY * 2 * PI / wave - PI / 2f) * amp + amp;
		}
		z2 += dZ;

		border = new Polygon2D();
		border.addPt(boundsCrop.x2, z2);
		border.addPt(boundsCrop.x2, boundsCrop.z1);
		// border.addPt(boundsCrop.x1,boundsCrop.z1);
		// border.addPt(boundsCrop.x1,zM);
		Bezier bez = new Bezier();
		bez.addControlPoint(boundsCrop.x1, boundsCrop.z1, 0);
		bez.addControlPoint(boundsCrop.x1, boundsCrop.z1 + 1, 0);
		bez.addControlPoint(boundsCrop.x1, boundsCrop.z1 + 1, 0);
		bez.addControlPoint(boundsCrop.x1, boundsCrop.z1 + 1.5f, 0);
		bez.addControlPoint(boundsCrop.x2 - 1, z2, 0);
		bez.addControlPoint(boundsCrop.x2, z2, 0);
		int nSegs = 100;
		for (int i = 0; i < nSegs; i++) {
			PVector p = bez.getPoint(i * 1f / nSegs);
			border.addPt(p.x, p.y);
		}

	}

	public Polygon2D crop2(float y) {
		float bumpY=0.20f;
		float z2 = boundsCrop.z2 -bumpY;
		float wave = 1.7f;
		float amp = bumpY/2f;
		float startY = -0.5f;
		float dZ = 0;
		float cY = y - startY;
		if (cY > 0 && cY < wave) {
			dZ = sin(cY * 2 * PI / wave - PI / 2f) * amp + amp;
		}
		Polygon2D border = new Polygon2D();
		border.addPt(boundsCrop.x2, z2);
		border.addPt(boundsCrop.x2, boundsCrop.z1);
		border.addPt(boundsCrop.x1,boundsCrop.z1);
		int nSegs = 100;
		float r = boundsCrop.getDimX();
		float sY=1;
		float scaleY=(boundsCrop.getDimZ()-sY-bumpY)/r;
		float bumpXStart=-1f;
		float bumpXEnd=0;
		float bumpDimX=bumpXEnd-bumpXStart;
		for (int iX = 0; iX < nSegs; iX++) {
			float cX = iX * r / nSegs;
			float dY = sqrt(sq(r) - sq(r-cX) )*scaleY+sY;
			float pX = cX + boundsCrop.x1;
			float pY = dY+boundsCrop.z1;
			
			if (pX>bumpXStart){
				float deltaX=(pX-bumpXStart)/bumpDimX;
				float newdeltaX=1-abs(pow(bumpDimX-deltaX,2f))/abs(pow(bumpDimX,2f));
				deltaX=(deltaX+1*newdeltaX)/2f;
				float addY=(sin(PI*deltaX-HALF_PI)+1f)/2f;
				pY+=dZ*addY;
			}
			border.addPt(pX, pY);
		}
		return border;
	}
	
	public void crop3(float y) {
		// if (outsideCrop) distance to line
		// if (insideCrop and unreached)
		float bumpY=0.5f;
		float z2 = boundsCrop.z2 -bumpY;
		// smaller iso->inside
		float zM = 1.5f;
		
		float amp = bumpY/2f;
		float startY = boundsCrop.y1;
		float midY=0.3f;
		float wave1 =midY- startY;
		float wave2 =boundsCrop.y2- midY;
		float dZ = 0;
		float cY = y - startY;
		if (y <midY ) {
			cY = y - startY;
			dZ = sin(cY *  PI / wave1 - PI / 2f) * amp + amp;
		}
		if (y >= midY ) {
			cY = y - midY;
			dZ = sin(cY  * PI / wave2 +PI / 2f) * amp + amp;
		}
		// z2+=dZ;
		
		border = new Polygon2D();
		border.addPt(boundsCrop.x2, z2);
		border.addPt(boundsCrop.x2, boundsCrop.z1);
		border.addPt(boundsCrop.x1,boundsCrop.z1);
		

		int nSegs = 100;
		float r = boundsCrop.getDimX();
		float sY=1;
		float scaleY=(boundsCrop.getDimZ()-sY-bumpY)/r;
		
		float bumpXStart=boundsCrop.x1;
		float bumpXEnd=0;
		float bumpDimX=bumpXEnd-bumpXStart;
		
		for (int iX = 0; iX < nSegs; iX++) {
			float cX = iX * r / nSegs;
			float dY = sqrt(sq(r) - sq(r-cX) )*scaleY+sY;
			float pX = cX + boundsCrop.x1;
			float pY = dY+boundsCrop.z1;
			float addY=(sin(PI*(pX-bumpXStart)/bumpDimX-HALF_PI)+1f)/2f;
			pY+=dZ*addY;
			border.addPt(pX, pY);
		}
		/*
		 * for (int i = 0; i < nSegs; i++) { PVector p = bez.getPoint(i * 1f /
		 * nSegs); border.addPt(p.x, p.y); }
		 */

	}
}
